package com.otree.aop;

import com.otree.dao.SysLogDao;
import com.otree.entity.SysLogEntity;
import com.otree.entity.SysUserEntity;
import com.otree.utils.IpUtil;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class SomeAespect {

    @Autowired
    private SysLogDao sysLogDao;
    @Autowired
    private HttpServletRequest requests;
    private long start;
    private long end;
    private static Logger logger = Logger.getLogger("controller");
    @Pointcut("execution(* com.otree.controller.*.*(..))")
    public void pointCut_(){
    }

    @Before(value="pointCut_()")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        Object args = Arrays.asList(joinPoint.getArgs());
        start = System.currentTimeMillis();
        logger.info("The method:"+methodName +" begins with "+ args);
    }


    /**
     * 	后置通知：在目标方法之后(无论是否发生异常)，执行的通知，
     在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。
     * @Title: afterMethod
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @param joinPoint    参数
     * @return void    返回类型
     * @throws
     */
    @After(value="pointCut_()")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        String className= joinPoint.getTarget().getClass().getName();
        end = System.currentTimeMillis();
        addLog(joinPoint, className);
        logger.info("The method:"+ methodName+" ends"+"执行业务方法共计：" + (end - start) + "毫秒");
    }
    /**
     * 返回通知：在目标方法正常结束执行后的通知
     * @Title: afterRunningMethod
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @param joinPoint
     * @param @param result    参数
     * @return void    返回类型
     * @throws
     */
    @AfterReturning(value="pointCut_()",returning="result")
    public void afterRunningMethod(JoinPoint joinPoint , Object result){
        String methodName = joinPoint.getSignature().getName();
//        addLog(joinPoint, methodName+result.toString());
        logger.info("The method:"+ methodName+" ends with the Result "+ result);
    }
    /**
     * 环绕通知
     * @Title: aroundAdvice
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @param proceedingJoinPoint
     * @param @return
     * @param @throws Throwable    参数
     * @return Object    返回类型
     * @throws
     */
    //@Around(value="pointCut_()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        String  methodName = proceedingJoinPoint.getSignature().getName();
        Object args = Arrays.asList(proceedingJoinPoint.getArgs());
        try {
            logger.info("Arround:The method "+methodName +" begins with "+args);
            long start = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            long end = System.currentTimeMillis();
            logger.info("Arround:The method "+ methodName+" ends"+","+"执行业务方法共计：" + (end - start) + "毫秒。");
        } catch(Exception e){
            e.printStackTrace();
            logger.info("Arround:异常监控 "+ methodName+"occurs exception:"+e);
            throw new RuntimeException(e);
        }
        logger.info("Arround:The method "+ methodName+" ends with the Result "+ result);
        return result;
    }
    /**
     * 异常通知
     * @Title: throwingAdvice
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @param joinPoint
     * @param @param e    参数
     * @return void    返回类型
     * @throws
     */

    @AfterThrowing(value="pointCut_()",throwing = "e")
    public void throwingAdvice(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        addLog(joinPoint, methodName + e.getMessage());
        logger.info("异常监控:" + methodName + " occurs exception: " + e);
    }


    private void addLog(JoinPoint jp, String text) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        SysUserEntity username = (SysUserEntity)requests.getSession().getAttribute("user");
        String methodName = jp.getSignature().getName();
        Object args = Arrays.asList(jp.getArgs());
        String ip = IpUtil.getIp(request);
        SysLogEntity log = new SysLogEntity();
        log.setIp(ip);
        log.setCreateDate(new Date());
        log.setMethod(methodName);
        log.setOperation(text);
        log.setParams(args.toString());
        if (username != null) {
            log.setUsername(username.getUsername());
            sysLogDao.save(log);
        }
    }
//    private String getDesc(JoinPoint joinPoint) {
//        MethodSignature methodName = (MethodSignature) joinPoint.getSignature();
//        Method method = methodName.getMethod();
//        return method.getAnnotation(Log.class).desc();
//    }
//    private Log.LOG_TYPE getType(JoinPoint joinPoint) {
//        MethodSignature methodName = (MethodSignature) joinPoint.getSignature();
//        Method method = methodName.getMethod();
//        return method.getAnnotation(Log.class).type();
//    }
}

